package ecnu.ecgbackend.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import ecnu.ecgbackend.dao.*;
import ecnu.ecgbackend.entity.*;
import ecnu.ecgbackend.service.DiagnosisAiDiagnosisService;
import ecnu.ecgbackend.utils.ResponseObject;
import ecnu.ecgbackend.utils.StatusObject;
import ecnu.ecgbackend.utils.TaskObject;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

@Service
@Transactional
public class DiagnosisAiDiagnosisServiceImpl implements DiagnosisAiDiagnosisService {
    @Resource
    RawDataMapper rawDataMapper;
    @Resource
    PatientMapper patientMapper;
    @Resource
    DeveloperMapper developerMapper;
    @Resource
    UserMapper userMapper;
    @Resource
    ArtificialDiagnosisMapper artificialDiagnosisMapper;


    // 创建 ByteArrayResource 以便将文件作为请求参数传递
    private static ByteArrayResource createByteArrayResource(String filePath) throws IOException {
        Path path = Paths.get(filePath);
        byte[] data = Files.readAllBytes(path);
        return new ByteArrayResource(data) {
            @Override
            public String getFilename() {
                return path.getFileName().toString();
            }
        };
    }
    //进行静态心电图智能诊断
    @Override
    public String doStaticDiagnosis(int samplingRate,double inputUnitMv,String filePath) throws IOException {
        // 构建请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        // 构建请求参数
        MultiValueMap<String, Object> parameters = new LinkedMultiValueMap<>();
        parameters.add("sampling_rate",samplingRate);
        parameters.add("inputUnit_mv",inputUnitMv);
        parameters.add("input_data",createByteArrayResource(filePath));
        // 构建请求体
        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(parameters, headers);
        // 发送 POST 请求
        RestTemplate restTemplate = new RestTemplate();
        String url = "http://106.15.43.0:7002/api/v2/predict";
        ResponseEntity<String> response = restTemplate.postForEntity(url, requestEntity, String.class);
        // 输出响应结果
        return response.getBody();
    }
    //进行动态心电图智能诊断
    public String doDynamicDiagnosis(String localPath,Map<String,Object> ecgMetaInfo,Map<String,Object> userInfo){
        // 构建请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        // 构建请求参数
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("local_path",localPath);
        parameters.put("ecg_meta_info",ecgMetaInfo);
        parameters.put("user_info",userInfo);
        System.out.println("localPath: "+localPath);
        System.out.println("parameters: "+parameters.toString());
        System.out.println("local_path: "+localPath);
        // 构建请求体
        HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(parameters, headers);
        // 发送 POST 请求
        RestTemplate restTemplate = new RestTemplate();
        String url = "http://106.15.43.0:7001/add_task_async";
        ResponseEntity<String> response = restTemplate.postForEntity(url, requestEntity, String.class);
        // 输出响应结果
        System.out.println("Response: " + response.getBody());
        return response.getBody();
    }

    @Override
    public ResponseObject saveStaticDiagnosis(String fileName) throws IOException {
        User user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String rawDataId=user.getId()+"_"+fileName;
        System.out.println("rawDataId: "+rawDataId);
        String filePath=rawDataMapper.selectOne(new QueryWrapper<RawData>().eq("raw_data_id",rawDataId)).getFilePathLocal();
        String response=doStaticDiagnosis(500,0.0024,filePath);
        ObjectMapper mapper=new ObjectMapper();
        ResponseObject responseObject=mapper.readValue(response,ResponseObject.class);
        return responseObject;
    }

    @Override
    public TaskObject saveDynamicDiagnosis(String fileName) throws IOException {
        User _user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String rawDataId=_user.getId()+"_"+fileName;
        String localPath=rawDataMapper.selectOne(new QueryWrapper<RawData>().eq("raw_data_id",rawDataId)).getFilePathLocal();
        Map<String,Object> ecgMetaInfo=new HashMap<>();
        int[] lead={1,2,3,4};
        ecgMetaInfo.put("filename",fileName);
        ecgMetaInfo.put("data_type","dat");
        ecgMetaInfo.put("sample_rate",250);
        ecgMetaInfo.put("lead",lead);
        Map<String,Object> userInfo=new HashMap<>();
        User user=userMapper.selectById(_user.getId());
        userInfo.put("name",user.getUsername());
        userInfo.put("age",user.getAge());
        userInfo.put("gender",user.getGender()==1?"man":"woman");
        String response=doDynamicDiagnosis(localPath,ecgMetaInfo,userInfo);
        ObjectMapper mapper=new ObjectMapper();
        TaskObject taskObject=mapper.readValue(response,TaskObject.class);
        return taskObject;
    }

    @Override
    public boolean editStaticRawDataStatus(String status,String rawDataId,String report) {
        UpdateWrapper<RawData> updateWrapper=new UpdateWrapper<>();
        if(report!=null){
            updateWrapper.eq("raw_data_id",rawDataId).set("status",status).set("report",report);
            System.out.println("=========================================================");
            System.out.println("raw_data_id: "+rawDataId);
            System.out.println("status: "+status);
            System.out.println("report: "+report);
            System.out.println("===========================================================");
        }else {
            updateWrapper.eq("raw_data_id",rawDataId).set("status",status);
        }
        if(rawDataMapper.update(null,updateWrapper)>0) {
            System.out.println("update true");
            return true;
        }
        return false;
    }

    @Override
    public boolean isIntegralEnough() {
        User _user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        User user=userMapper.selectById(_user.getId());
        if(user.getRole().equals("patient")){
            if(patientMapper.selectById(user.getId()).getIntegral()>0){
                return true;
            }else {
                return false;
            }
        }else if(user.getRole().equals("developer")){
            if(developerMapper.selectById(user.getId()).getIntegral()>0){
                return true;
            }else {
                return false;
            }
        }
        return false;
    }
    public static StatusObject parseStatus(String json) throws JsonProcessingException {
        // 定义正则表达式匹配online数组的模式
        Pattern pattern = Pattern.compile("\"online\":\\[(.*?)\\]");

        // 创建Matcher对象，并将json字符串传入进行匹配
        Matcher matcher = pattern.matcher(json);
        String extractedJson="{[]}";
        // 查找并输出匹配结果
        while (matcher.find()) {
            String onlineArray = matcher.group(1);
            System.out.println("提取出的Online数组字符串: " + onlineArray);

            // 将提取出的字符串作为单独的JSON字符串输出
             extractedJson = "{\"online\": [" + onlineArray + "]}";
            System.out.println("提取出的JSON字符串: " + extractedJson);
        }
        ObjectMapper mapper=new ObjectMapper();
        StatusObject statusObject=mapper.readValue(extractedJson,StatusObject.class);
        return statusObject;
    }
    //获取动态心电图智能诊断状态
    @Override
    public StatusObject getDynamicStatus(String taskId) throws IOException {

        // 发送 GET 请求
        RestTemplate restTemplate = new RestTemplate();
        String url = "http://106.15.43.0:7001/get_status?task_id="+taskId;
        System.out.println("getDynamicStatus url: "+url);
        ResponseEntity<String> response=restTemplate.getForEntity(url,String.class);
        // 输出响应结果
        System.out.println("Response: " + response.getBody());
        StatusObject status=parseStatus(response.getBody());
        UpdateWrapper<RawData> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("report",taskId).set("status",status.getOnline()[status.getOnline().length-1]);
        rawDataMapper.update(null,updateWrapper);
        return status;
    }

    @Override
    public Map<String, Object> getHistoryService(String category, int pageNum, int pageSize) throws IOException{
        Map<String,Object> result=new HashMap<>();
        User user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Page<RawData> page=new Page<>(pageNum,pageSize);
        QueryWrapper<RawData> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("patient_id",user.getId()).orderByDesc("update_date");
        if(!category.equals("none")){
            queryWrapper.eq("category",category);
        }
        int number=rawDataMapper.selectList(queryWrapper).size();
        List<RawData> rawDataList=rawDataMapper.selectPage(page,queryWrapper).getRecords();
        List<RawData> newRawDataList=rawDataList.stream().map(item->{
            if(item.getStatus().equals("nostart") || item.getStatus().equals("report")){
                return item;
            }else {
                if(item.getCategory().equals("static")){
                    return item;
                }else {
                    try {
                        getDynamicStatus(item.getReport());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    return rawDataMapper.selectOne(new QueryWrapper<RawData>().eq("raw_data_id",item.getRawDataId()));
                }
            }
        }).collect(Collectors.toList());
        List<Map<String,Object>> list= newRawDataList.stream().map(item->{
            Map<String,Object> record=new HashMap<>();
            record.put("rawData",item);
            ArtificialDiagnosis artificialDiagnosis=artificialDiagnosisMapper.selectOne(
                    new QueryWrapper<ArtificialDiagnosis>().eq("raw_data_id",item.getRawDataId())
                            .eq("patient_id",item.getPatientId()));
            record.put("artificialDiagnosis",artificialDiagnosis);
            if(artificialDiagnosis==null){
                record.put("doctorName",null);
            }else {
                record.put("doctorName", userMapper.selectById(artificialDiagnosis.getDoctorId()).getRealName());
            }
            return record;
        }).collect(Collectors.toList());
        result.put("history",list);
        result.put("number",number);
        return result;
    }
    //获取动态心电图智能诊断结果
    @Override
    public Map<String,Object> getDynamicResult(String rawDataId) {
        Map<String,Object> result=new HashMap<>();
        String taskId=rawDataMapper.selectOne(new QueryWrapper<RawData>().eq("raw_data_id",rawDataId)).getReport();
        try{
            URL url=new URL("http://106.15.43.0:7001/get_result_files?task_id="+taskId);
            HttpURLConnection connection= (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            int responseCode=connection.getResponseCode();
            if(responseCode==HttpURLConnection.HTTP_OK){
                InputStream inputStream=connection.getInputStream();
//                handleZipResponse(inputStream);
                ZipInputStream zipInputStream=new ZipInputStream(inputStream);
                ZipEntry entry;
                while ((entry= zipInputStream.getNextEntry())!=null){
                    String fileName=entry.getName();
                    if(!entry.isDirectory()){
                        if(fileName.endsWith(".txt") || fileName.endsWith(".json")){
                            ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
                            byte[] buffer=new byte[1024];
                            int bytesRead;
                            while ((bytesRead=zipInputStream.read(buffer))!=-1){
                                byteArrayOutputStream.write(buffer,0,bytesRead);
                            }
                            String fileContent=byteArrayOutputStream.toString("UTF-8");
                            String key=fileName.split("_")[1];
                            if(!key.equals("mybeats")) {
                                result.put(key, fileContent);
                            }
                        }
                    }
                    zipInputStream.closeEntry();
                }
                zipInputStream.close();
                inputStream.close();
            }else {
                System.out.println("Failed to get response. ResponseCode="+responseCode);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
        return result;
    }

        public static void handleZipResponse(InputStream inputStream)throws IOException{
        try(ZipInputStream zipInputStream=new ZipInputStream(inputStream)){
            ZipEntry entry;
            while ((entry=zipInputStream.getNextEntry())!=null){
                String fileName=entry.getName();
                File outputFile=new File(fileName);
                try(OutputStream outputStream=new FileOutputStream(outputFile)){
                    byte[] buffer=new byte[1024];
                    int bytesRead;
                    while ((bytesRead=zipInputStream.read(buffer))!=-1){
                        outputStream.write(buffer,0,bytesRead);
                    }
                    System.out.println("Extracted file: "+outputFile.getAbsolutePath());
                }
            }
        }
    }
        public static void handleZipResponse(org.apache.http.HttpEntity entity) throws IOException{
        try(InputStream inputStream=entity.getContent()){
            try(FileOutputStream outputStream=new FileOutputStream("downloaded.zip")){
                byte[] buffer=new byte[1024];
                int bytesRead;
                while ((bytesRead=inputStream.read(buffer))!=-1){
                    outputStream.write(buffer,0,bytesRead);
                }
            }
        }
    }
    //获取静态心电图智能诊断结果
    @Override
    public String getStaticResult(String rawDataId) {
        QueryWrapper<RawData> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("raw_data_id",rawDataId);
        RawData rawData=rawDataMapper.selectOne(queryWrapper);
        if(rawData==null){
            return "[\"未找到该文件\"]";
        }
        return rawData.getReport();
    }

    @Override
    public boolean editArtificialDiagnosisReport(String rawDataId, String patientId, String report) {
        User user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        UpdateWrapper<ArtificialDiagnosis> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("patient_id",patientId)
                .eq("doctor_id",user.getId())
                .eq("raw_data_id",rawDataId)
                .set("report",report)
                .set("status","done");
        if(artificialDiagnosisMapper.update(null,updateWrapper)>0){
            return true;
        }
        return false;
    }

}
